package hku.cs.lunuo;

import hku.cs.lunuo.tools.DirTools;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.XMLOutputter;
import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;

public class JunitListener4 extends RunListener{
	private File conPath = null;
	private HashMap<String, HashMap<String, Boolean>> result = new HashMap<String, HashMap<String, Boolean>>();
	private String resultDirPath;

	private Set<String> tmpSet = new HashSet<String>();

	public JunitListener4(String resultDirPath) {
		this.resultDirPath = resultDirPath;
		DirTools.newTest(resultDirPath);//fix bug, at first it is put at sesstionstart, but then
		//junit create result files, so clear the directory can't be complete.	
	}
	
	private boolean isSame(String a, String b) {
		if(a.startsWith(b)) {
			if(a.length()>b.length()) {
				if(a.charAt(b.length())=='.')
					return true;
				else return false;
			}else
				return true;
		}
		return false;
	}
	
	public boolean constructCate(Description test, Element xmlE) {			
		if (test.isTest()) {
			Element e = new Element("testmethod");
			String name = test.getDisplayName();
			name = name.substring(0, name.indexOf('('));
			
			int max = 0;
			boolean is = false;
			for(String s : tmpSet) {
				if(isSame(s,name)) {
					String[] xx = s.split("\\.");
					if(xx.length==2 ) {
						if( Integer.parseInt(xx[1])>max)
							max = Integer.parseInt(xx[1]);
					}
					is = true;
				}
			}
			if(is) {
				max++;
				name+="."+max;
			}
			
			e.setAttribute("name", name);
			tmpSet.add(name);
			xmlE.addContent(e);
			return false;
		} else if (test.isSuite()) {
			Element e = new Element("testsuite");
			String naxx = test.getDisplayName();
			if("".equals(naxx))
				naxx = "Anonymous_Testsuite";
			if(naxx.indexOf('(') != -1)
				naxx = naxx.substring(0, naxx.indexOf('('));
			e.setAttribute("name", naxx);
			xmlE.addContent(e);
			boolean isTestCase = true;
			List<Description> ites= test.getChildren();
			for (Description ite : ites) {
				if (constructCate(ite, e)) {
					isTestCase = false;
				}
			}
			if (isTestCase) {
				e.setName("testcase");
				tmpSet.clear();
			}
			return true;
		}
		return true;
	}
	
	
	boolean currentTestResult = true;
	public void testStarted(Description description) throws Exception {
		currentTestResult = true;
	}

	
	/** 
	 * Called when an atomic test fails.
	 * @param failure describes the test that failed and the exception that was thrown
	 */
	public void testFailure(Failure failure) throws Exception {
		currentTestResult = false;
//		System.out.println(failure.getMessage());
	}
	
	
	@Override
	public void testFinished(Description des) throws Exception {
		String testName = des.getDisplayName();
		String testCaseName = testName.substring(testName.indexOf('(')+1, testName.indexOf(')'));
		testName = testName.substring(0, testName.indexOf('('));
		
		HashMap<String, Boolean> inMap = result.get(testCaseName);
		
		if (inMap == null)
			inMap = new HashMap<String, Boolean>();
		
		int max = 0;
		boolean is = false;
		for(String s : inMap.keySet()) {
			if(s.startsWith(testName)) {
				String[] xx = s.split("\\.");
				if(xx.length==2 ) {
					if( Integer.parseInt(xx[1])>max)
						max = Integer.parseInt(xx[1]);
				}
				is = true;
			}
		}
		if(is) {
			max++;
			testName+="."+max;
		}
		inMap.put(testName, currentTestResult);
		result.put(testCaseName, inMap);
	}

	@Override
	public void testRunFinished(Result r) throws Exception {
		for (String rkey : result.keySet()) {
			HashMap<String, Boolean> inResult = result.get(rkey);

			Element xmlRoot = new Element("testcase");
			xmlRoot.setAttribute("name", rkey);
			xmlRoot.setAttribute("number", Integer.toString(inResult.size()));
			Document xmlDoc = new Document(xmlRoot);

			for (String key : inResult.keySet()) {
				Element xmlTestMethod = new Element("testmethod");
				xmlTestMethod.setAttribute("name", key);
				xmlTestMethod.setAttribute("status", ((Boolean) inResult
						.get(key)).toString());
				xmlRoot.addContent(xmlTestMethod);
			}

			try {
				File f = DirTools.prepare(new File(resultDirPath, rkey));
				File fz = new File(f, "result.xml");
				new XMLOutputter().output(xmlDoc, new FileOutputStream(fz));
				System.out.println("write result file to " + fz.toString());
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
//
//			
//		Scene.v().setSootClassPath(LunuoLibHelper
//				.urlsToString(sootclassPath));
//
//		
//		for (String rkey : result.keySet()) {
//			HashMap<String, Boolean> inResult = result.get(rkey);
//			String tmp = resultDirPath + rkey + File.separator;
//			for (String key : inResult.keySet()) {
//				String[] args = new String[] { tmp + key + File.separator };
//				Check.main(args);
//			}
//
//		}
	}

	@Override
	public void testRunStarted(Description des) throws Exception {
		int a = resultDirPath.lastIndexOf('/');
		int b = resultDirPath.lastIndexOf('/', resultDirPath.length()-2);
		String c = resultDirPath.substring(b+1, a);
	
		Element xmlRoot = new Element("Test_Session");
		xmlRoot.setAttribute("name", c);
		Document xmlDoc = new Document(xmlRoot);
		
		List<Description> topSuite = des.getChildren();
		
		for (Description ite : topSuite)
			constructCate(ite, xmlRoot);

		try {
			conPath = new File(resultDirPath, "construct.xml");
			new XMLOutputter().output(xmlDoc, new FileOutputStream(conPath));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
}
